package com.tyk.bookstore.front.cart.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.front.cart.model.entity.CartDo;
import com.tyk.bookstore.front.cart.model.query.CartAddQuery;
import com.tyk.bookstore.front.cart.model.query.CartPageQuery;
import com.tyk.bookstore.front.cart.model.query.CartUpdateQuery;
import com.tyk.bookstore.front.cart.model.result.CartResultEnum;
import com.tyk.bookstore.front.cart.model.vo.CartPageVo;
import com.tyk.bookstore.front.cart.model.vo.ShoppingCartVo;
import com.tyk.bookstore.front.cart.repository.CartRepository;
import com.tyk.bookstore.front.cart.service.CartService;
import com.tyk.bookstore.front.cart.util.MapStructCart;
import com.tyk.bookstore.front.common.core.util.AssertUtil;
import com.tyk.bookstore.front.product.model.dto.Book4CartDto;
import com.tyk.bookstore.front.product.model.enume.BookState;
import com.tyk.bookstore.front.product.service.BookApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 购物车管理
 */
@Service
@RequiredArgsConstructor
public class CartServiceImp implements CartService {

    private final CartRepository cartRepository;
    private final BookApiService bookApiService;
    private final TransactionTemplate transactionTemplate;
    private final MapStructCart mapStructCart;

    @Override
    public ShoppingCartVo getByBookId(Long bookId) {

        Long memberId = StpUtil.getLoginIdAsLong();
        CartDo cart = cartRepository.selectCartByBookId(bookId, memberId);
        AssertUtil.notNull(cart, CartResultEnum.CART_NOT_FOUND);

        Book4CartDto book = bookApiService.getBook4CartDtoById(bookId);

        return mapStructCart.toShoppingCartVo(cart, book);
    }

    @Override
    public CartPageVo getPage(CartPageQuery query) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 购物车信息
        Page<CartDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<CartDo> w = Wrappers.lambdaQuery();
        w.eq(CartDo::getMemberId, memberId)
                .orderBy(true, false, CartDo::getCreateTime);
        cartRepository.selectPage(page, w);
        CartPageVo cpv = mapStructCart.toShoppingCartPageVo(page);

        // 书籍信息
        Map<Long, Book4CartDto> map = bookApiService.getBook4CartDtoListByIdSet(
                cpv.getRecords().stream().map(CartPageVo.ShoppingCart::getBookId).collect(Collectors.toSet())
        ).stream().collect(Collectors.toMap(Book4CartDto::getId, it -> it));

        // 购物车中待删除的书籍
        HashSet<Long> wdSet = new HashSet<>();
        // 购物车中待取消勾选的书籍
        HashSet<Long> wcSet = new HashSet<>();

        // 补充书籍信息
        cpv.getRecords().forEach(it -> {
            // 购物车中的书籍存在
            if (map.containsKey(it.getBookId())) {
                // 购物车项
                Book4CartDto bk = map.get(it.getBookId());
                it.setCover(bk.getCover())
                        .setTitle(bk.getTitle())
                        .setPrice(bk.getPrice())
                        .setState(bk.getState());
                // 购物车中已下架的商品
                if (bk.getState() == BookState.OFF) {
                    it.setChecked(false);
                    wcSet.add(it.getBookId());
                }
            }
            // 购物车中的书籍不存在
            else wdSet.add(it.getBookId());
        });


        // 将购物车中待删除商品删除
        cartRepository.delete1In1Eq(
                CartDo::getBookId, wdSet,
                CartDo::getMemberId, memberId,
                CartDo.class
        );

        // 将购物车中待取消勾选商品取消勾选
        cartRepository.update1Set2Eq(
                CartDo::getChecked, 0,
                CartDo::getBookId, wcSet,
                CartDo::getMemberId, memberId,
                CartDo.class
        );

        return cpv;
    }

    @Override
    public List<ShoppingCartVo> getList() {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 购物车信息
        LambdaQueryWrapper<CartDo> w = Wrappers.lambdaQuery();
        w.eq(CartDo::getMemberId, memberId)
                .orderBy(true, false, CartDo::getCreateTime);
        List<CartDo> doList = cartRepository.selectList(w);

        // 书籍信息
        Map<Long, Book4CartDto> map = bookApiService.getBook4CartDtoListByIdSet(
                doList.stream().map(CartDo::getBookId).collect(Collectors.toSet())
        ).stream().collect(Collectors.toMap(Book4CartDto::getId, it -> it));

        // 购物车中待删除的书籍
        HashSet<Long> wdSet = new HashSet<>();
        // 购物车中待取消勾选的书籍
        HashSet<Long> wcSet = new HashSet<>();

        // 补充书籍信息
        List<ShoppingCartVo> svList = new ArrayList<>();
        doList.forEach(it -> {
            // 购物车中的书籍存在
            if (map.containsKey(it.getBookId())) {
                // 购物车项
                ShoppingCartVo sv = mapStructCart.toShoppingCartVo(it, map.get(it.getBookId()));
                // 购物车中已下架的商品
                if (sv.getState() == BookState.OFF) {
                    it.setChecked(false);
                    wcSet.add(it.getBookId());
                }
                // 书籍存在的购物车项
                svList.add(sv);
            }
            // 购物车中的书籍不存在
            else wdSet.add(it.getBookId());
        });

        // 将购物车中待删除商品删除
        cartRepository.delete1In1Eq(
                CartDo::getBookId, wdSet,
                CartDo::getMemberId, memberId,
                CartDo.class
        );

        // 将购物车中待取消勾选商品取消勾选
        cartRepository.update1Set1In1Eq(
                CartDo::getChecked, false,
                CartDo::getBookId, wcSet,
                CartDo::getMemberId, memberId,
                CartDo.class
        );

        // 返回购物车数据
        return svList;
    }

    @Override
    public void selectAllOrCancelAll(Boolean isAllSelected) {
        long memberId = StpUtil.getLoginIdAsLong();
        cartRepository.selectAllOrCancelAll(isAllSelected, memberId);
    }

    @Override
    public void cleanOffProduct() {
        long memberId = StpUtil.getLoginIdAsLong();
        transactionTemplate.executeWithoutResult(status -> {
            // 会员收藏的所有商品
            Set<Long> cs = cartRepository.
                    <BigInteger>selectSinList1Eq(
                    CartDo::getBookId,
                    CartDo::getMemberId, memberId,
                    CartDo.class
            ).stream().map(it -> it.getV1().longValue()).collect(Collectors.toSet());
            // 筛选已下架商品
            Set<Long> bs = new HashSet<>(bookApiService.getOffIdListByIdSet(cs));
            // 删除已下架商品
            cartRepository.delete1In1Eq(
                    CartDo::getBookId, bs,
                    CartDo::getMemberId, memberId,
                    CartDo.class
            );
        });
    }

    @Override
    public void add(CartAddQuery query) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 书籍存在
        bookApiService.assertExistByIdSet(Set.of(query.getBookId()));

        // 加入购物车
        transactionTemplate.executeWithoutResult(status -> {
            // 查询商品在购物车中的数量
            LambdaQueryWrapper<CartDo> w1 = Wrappers.lambdaQuery(CartDo.class);
            w1.select(CartDo::getNum)
                    .eq(CartDo::getBookId, query.getBookId())
                    .eq(CartDo::getMemberId, memberId);
            CartDo cart = cartRepository.selectOne(w1);
            // 商品不在购物车则将商品加入购物车
            if (cart == null) {
                cart = mapStructCart.toCartDo(query).setMemberId(memberId).setChecked(true);
                cartRepository.insert(cart);
            }
            // 商品在购物车则进行数量合并
            else {
                LambdaUpdateWrapper<CartDo> w2 = Wrappers.lambdaUpdate(CartDo.class);
                w2.set(CartDo::getNum, query.getNum() + cart.getNum())
                        .set(CartDo::getChecked, true)
                        .eq(CartDo::getBookId, query.getBookId())
                        .eq(CartDo::getMemberId, memberId);
                cartRepository.update(w2);
            }
        });

    }

    @Override
    public void update(CartUpdateQuery query) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 书籍存在
        bookApiService.assertExistById(query.getBookId());

        // 购物车存在
        AssertUtil.isTrue(
                cartRepository.exist2Eq(
                        CartDo::getBookId, query.getBookId(),
                        CartDo::getMemberId, memberId,
                        CartDo.class
                ),
                CartResultEnum.CART_NOT_FOUND
        );

        // 更新
        CartDo cart = mapStructCart.toCartDo(query);
        cart.setMemberId(memberId);
        LambdaUpdateWrapper<CartDo> w = Wrappers.lambdaUpdate(CartDo.class);
        w.set(CartDo::getNum, query.getNum())
                .set(CartDo::getChecked, query.getChecked())
                .eq(CartDo::getMemberId, memberId)
                .eq(CartDo::getBookId, query.getBookId());
        cartRepository.update(w);
    }

    @Override
    public void deleteByBookId(Long bookId) {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 购物车存在
        AssertUtil.isTrue(
                cartRepository.exist2Eq(
                        CartDo::getBookId, bookId,
                        CartDo::getMemberId, memberId,
                        CartDo.class
                ),
                CartResultEnum.CART_NOT_FOUND
        );

        // 删除
        cartRepository.delete2Eq(
                CartDo::getBookId, bookId,
                CartDo::getMemberId, memberId,
                CartDo.class
        );

    }

    @Override
    public void deleteBatchByBookIdSet(Set<Long> bookIdSet) {

        if (bookIdSet.isEmpty()) return;

        Long memberId = StpUtil.getLoginIdAsLong();

        // 购物车存在
        AssertUtil.equal(
                cartRepository.count1In1Eq(
                        CartDo::getBookId, bookIdSet,
                        CartDo::getMemberId, memberId,
                        CartDo.class
                ),
                (long) bookIdSet.size(),
                CartResultEnum.CART_NOT_FOUND
        );

        // 删除
        cartRepository.delete1In1Eq(
                CartDo::getBookId, bookIdSet,
                CartDo::getMemberId, memberId,
                CartDo.class
        );
    }


}
